package com.zws.cucumber.plugin.procedure;

import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.pattern.Converter;
import ch.qos.logback.core.pattern.PostCompileProcessor;

import static com.zws.cucumber.util.colorfullog.ZwsColorfulLogHelper.*;

public class ZwsProcedureLoggerLayout extends PatternLayout implements PostCompileProcessor<ILoggingEvent> {

    static final int INTIAL_STRING_BUILDER_SIZE = 256;

    Converter<ILoggingEvent> head;

    public ZwsProcedureLoggerLayout() {

    }

    public ZwsProcedureLoggerLayout(PatternLayout other) {
        this.setContext(other.getContext());
        this.setPattern(other.getPattern());
        this.setPostCompileProcessor(this);
        start();
    }

    @Override
    public void process(Context context, Converter<ILoggingEvent> head) {
        this.head = new ProcedureDepthConverter(head);
    }

    @Override
    protected String writeLoopOnConverters(ILoggingEvent event) {

        StringBuilder strBuilder = new StringBuilder(INTIAL_STRING_BUILDER_SIZE);
        Converter<ILoggingEvent> c = head;
        while (c != null) {
            c.write(strBuilder, event);
            c = c.getNext();
        }
        return strBuilder.toString();
    }

    public static class ProcedureDepthConverter extends Converter<ILoggingEvent> {

        private static final String[] Prefixes = new String[] {
                render("/", FG_CYAN),
                render("/", FG_YELLOW),
                render("/", FG_BLUE),
                render("/", FG_PURPLE),
        };

        private static String prefix(int i) {
            if (i == 1) {
                return Prefixes[0];
            }
            return prefix(i - 1) + Prefixes[(i - 1) % Prefixes.length];
        }

        public static final String[] Slashes = new String[]{
                "",
                prefix(1) + render("1 ", FG_CYAN),
                prefix(2) + render("2 ", FG_YELLOW),
                prefix(3) + render("3 ", FG_BLUE),
                prefix(4) + render("4 ", FG_PURPLE),
                prefix(5) + render("5 ", FG_CYAN),
                prefix(6) + render("6 ", FG_YELLOW),
                prefix(7) + render("7 ", FG_BLUE),
                prefix(8) + render("8 ", FG_PURPLE),
        };

        public ProcedureDepthConverter(Converter<ILoggingEvent> next) {
            setNext(next);
        }

        @Override
        public String convert(ILoggingEvent event) {
            int level = ZwsProcedureUtil.invokingLevel();
            if (level == 0) {
                return "";
            } else if (level <= 8) {
                return Slashes[level];
            }
            throw new IllegalArgumentException("Unsupported depth: " + level);
        }
    }
}
